"""Git 项目上传工具"""

import os
import subprocess
from typing import List

import requests
from loguru import logger
import fire


def run_command_in_dir(command: str, directory: str, debug: bool = True):
    """
    在指定目录下执行命令并返回控制台输出

    :param command: 要执行的命令
    :param directory: 执行命令的目录路径
    :return: 命令的输出结果
    """

    ret = None

    # 使用 subprocess.run 执行命令并捕获输出
    try:
        result = subprocess.run(
            command,
            shell=True,
            cwd=directory,
            text=True,
            capture_output=True,
            check=True,
        )
        # 返回命令的输出结果
        ret = result.stdout + result.stderr
    except subprocess.CalledProcessError as e:
        logger.error(
            f"在目录 {directory} 下执行命令({command})失败, 错误信息: {str(e)}"
        )
        ret = e.stdout + e.stderr

    if debug:
        logger.debug(
            f"在目录 {directory} 下执行命令({command})的输出结果: {ret if ret else '无'}"
        )

    return ret


def find_git_repositories(root_dir) -> List[str]:
    """
    遍历目录并获取目录下所有 git 项目目录路径

    :param root_dir: 要遍历的根目录路径
    :return: 在 root_dir 下所有 git 仓库路径的列表
    """

    git_repositories = []
    for dirpath, dirnames, filenames in os.walk(root_dir):
        # 检查当前目录是否包含 .git 目录
        if ".git" in filenames or os.path.exists(os.path.join(dirpath, ".git", "HEAD")):
            git_repositories.append(dirpath)
            # 如果当前目录是 git 仓库, 则不需要继续遍历其子目录
            dirnames.clear()
        else:
            # 排除掉不需要遍历的目录
            dirnames[:] = [dn for dn in dirnames if not dn.startswith(".")]
    return git_repositories


def is_git_repository(path) -> bool:
    """
    判断指定路径是否是 git 仓库

    :param path: 要检查的目录路径
    :return: 如果是 git 仓库返回 True, 否则返回 False
    """

    # 检查路径是否存在
    if not os.path.exists(path):
        return False

    # 检查路径是否是目录
    if not os.path.isdir(path):
        return False

    # 检查是否存在 .git 目录
    git_dir = os.path.join(path, ".git")
    return os.path.isdir(git_dir)


class GiteeClient:
    """Gitee 客户端"""

    def __init__(self, access_token: str, remote_ssh_path: str):
        """初始化 Gitee 客户端"""

        self.access_token = access_token
        self.remote_ssh_path = remote_ssh_path

    def create_gitee_repo(self, **kwargs):
        """创建 gitee 仓库

        参考 API 文档构造入参: https://help.gitee.com/openapi/v5#tag/repositories/POST/v5/user/repos
        """

        url = "https://gitee.com/api/v5/user/repos"
        headers = {"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"}
        data = {
            "access_token": self.access_token,
            **kwargs,
        }
        response = requests.post(
            url,
            headers=headers,
            data=data,
        )
        json_r = response.json()
        if "url" not in json_r:
            logger.error(f"创建 gitee 仓库失败: {json_r}")
            return
        url = json_r["url"]
        logger.success(f"创建的 gitee 仓库地址: {url}")

    def upload_to_gitee(self, dir_path: str, repo_name: str):
        """将 git 文件夹上传到 gitee"""

        logger.info("开始将 git 文件夹上传到 gitee")

        _ = run_command_in_dir(
            command=f"git remote set-url origin {self.remote_ssh_path}/{repo_name}.git",
            directory=dir_path,
        )
        _ = run_command_in_dir(command="git add .", directory=dir_path)
        _ = run_command_in_dir(command="git commit -am 'init'", directory=dir_path)
        _ = run_command_in_dir(command="git push", directory=dir_path)

        logger.success(f"仓库 {repo_name} 上传完成")


def upload_git_project_to_gitee(
    source_git_dir: str, gitee_access_token: str, gitee_remote_ssh_path: str
):
    """上传本地 git 项目到 gitee

    Args:
        source_git_dir (str): 本地 git 项目目录的父目录路径
        gitee_access_token (str): 你的 gitee access token
        gitee_remote_ssh_path (str): 你的 gitee remote ssh path, 例如: git@gitee.com:lan-tianyou
    """

    cli = GiteeClient(
        access_token=gitee_access_token,
        remote_ssh_path=gitee_remote_ssh_path,
    )

    logger.info(f"开始遍历 {source_git_dir} 目录下的所有 git 仓库")
    repos = find_git_repositories(source_git_dir)
    logger.info(f"{len(repos)} repos found: {repos}")

    for repo_dir_path in repos:
        # 校验仓库路径对应的是否是 git 仓库并获取仓库名
        logger.info(f"准备将仓库 {repo_dir_path} 上传到 gitee")
        if is_git_repository(repo_dir_path):
            logger.info(f"{repo_dir_path} 是个 git 仓库")
        else:
            logger.warning(f"{repo_dir_path} 不是个 git 仓库")
            continue
        repo_name = os.path.basename(repo_dir_path)
        logger.info(f"仓库名: {repo_name}")

        # 创建 gitee 仓库
        cli.create_gitee_repo(
            name=repo_name,
            description=repo_name,
            private=True,
            auto_init=False,
        )

        # 将本地 git 项目上传到 gitee 仓库
        cli.upload_to_gitee(dir_path=repo_dir_path, repo_name=repo_name)


# python main.py {git project parent dir path} {gitee access token} {gitee remote ssh path}
if __name__ == "__main__":
    fire.Fire(upload_git_project_to_gitee)
